package com.lap.framework.junit.shared.tool;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.web.bind.annotation.*;

@UtilityClass
public class AnnotationUtil {

  public static String getRequestMappingUri(Class<?> clazz) {
    if (clazz == null) {
      return null;
    }

    RequestMapping mapping = clazz.getAnnotation(RequestMapping.class);
    return mapping != null && mapping.value().length > 0 ? mapping.value()[0] : null;
  }

  public static Pair<String, String> getHttpMethodAndUri(Method method) {
    return Stream.of(
            checkAnnotation(method, PostMapping.class, "PostMapping"),
            checkAnnotation(method, GetMapping.class, "GetMapping"),
            checkAnnotation(method, PutMapping.class, "PutMapping"),
            checkAnnotation(method, DeleteMapping.class, "DeleteMapping"))
        .filter(Objects::nonNull)
        .findFirst()
        .orElse(Pair.of(null, null));
  }

  private static <T extends Annotation> Pair<String, String> checkAnnotation(
      Method method, Class<T> annotationClass, String methodType) {
    T annotation = method.getAnnotation(annotationClass);
    if (annotation != null) {
      String[] values = getAnnotationValue(annotation);
      return Pair.of(UriUtil.getFirstUri(values), methodType);
    }
    return null;
  }

  private static String[] getAnnotationValue(Annotation annotation) {
    if (annotation instanceof PostMapping) {
      return ((PostMapping) annotation).value();
    } else if (annotation instanceof GetMapping) {
      return ((GetMapping) annotation).value();
    } else if (annotation instanceof PutMapping) {
      return ((PutMapping) annotation).value();
    } else if (annotation instanceof DeleteMapping) {
      return ((DeleteMapping) annotation).value();
    }
    return new String[0];
  }

  public static boolean hasPathVariable(String uri) {
    return uri != null && Pattern.compile("\\{(.*?)\\}", Pattern.DOTALL).matcher(uri).find();
  }
}
